from typing import Dict, Any, List, Optional, Set
import os
from datetime import datetime
from .base_reporter import BaseReporter, ReporterError
from .reporter_factory import ReporterFactory
from ..services.base_service_handler import ServiceHandlerFactory
from ...logger import get_logger

logger = get_logger()

class Reporter:
    """端口扫描报告生成器"""
    
    VALID_FORMATS = {'all', 'txt', 'json', 'html', 'csv'}
    
    def __init__(self, output_format: str = 'all'):
        """初始化报告生成器
        
        Args:
            output_format: 报告输出格式，可选值：'all'、'txt'、'json'、'html'、'csv'
            
        Raises:
            ValueError: 当output_format不是有效的格式时
        """
        if output_format not in self.VALID_FORMATS:
            raise ValueError(f"无效的输出格式: {output_format}. 有效格式为: {', '.join(self.VALID_FORMATS)}")
            
        self.output_format = output_format
        self.timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        self.results = []
        self.scan_info = {}
        
        try:
            # 创建基础结果目录
            self.result_dir = 'result'
            os.makedirs(self.result_dir, exist_ok=True)
            
            # 创建本次扫描的时间戳目录
            self.scan_dir = os.path.join(self.result_dir, self.timestamp)
            os.makedirs(self.scan_dir, exist_ok=True)
            
            logger.info(f"扫描结果将保存到目录: {self.scan_dir}")
        except OSError as e:
            logger.error(f"创建目录时发生错误: {str(e)}")
            raise ReporterError(f"创建输出目录失败: {str(e)}")
    
    def __enter__(self):
        """进入上下文管理器"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """退出上下文管理器时自动生成报告"""
        if exc_type is not None:
            # 如果发生异常，记录错误但不抛出
            logger.error(f"扫描过程中发生错误: {exc_type.__name__}: {str(exc_val)}")
            return False
            
        try:
            if self.results:  # 只在有结果时生成报告
                self.generate_report(self.results, self.scan_info)
            return True
        except Exception as e:
            logger.error(f"生成报告时发生错误: {str(e)}")
            return False
    
    def add_result(self, result: Dict[str, Any]) -> None:
        """添加扫描结果
        
        Args:
            result: 单个扫描结果
        """
        self.results.append(result)
    
    def update_scan_info(self, scan_info: Dict[str, Any]) -> None:
        """更新扫描信息
        
        Args:
            scan_info: 扫描信息
        """
        self.scan_info.update(scan_info)
    
    def generate_report(self, results: List[Dict[str, Any]], scan_info: Dict[str, Any]) -> None:
        """生成扫描报告
        
        Args:
            results: 扫描结果列表
            scan_info: 扫描信息字典
            
        Raises:
            ReporterError: 当生成报告失败时
        """
        try:
            if not results:
                logger.warning("没有扫描结果可供报告")
                return
            
            # 获取报告生成器
            if self.output_format == 'all':
                reporters = ReporterFactory.get_all_reporters(self.scan_dir)
            else:
                reporters = {
                    self.output_format: ReporterFactory.get_reporter(
                        self.output_format,
                        self.scan_dir
                    )
                }
            
            # 生成报告
            for format_type, reporter in reporters.items():
                try:
                    logger.info(f"正在生成{format_type}格式报告...")
                    reporter.format_report(results, scan_info)
                    logger.info(f"{format_type}格式报告生成完成")
                except Exception as e:
                    logger.error(f"生成{format_type}格式报告时发生错误: {str(e)}")
                    if self.output_format != 'all':
                        raise
            
            logger.info("所有报告生成完成")
            
        except Exception as e:
            error_msg = f"生成报告时发生错误: {str(e)}"
            logger.error(error_msg)
            raise ReporterError(error_msg)
    
    @staticmethod
    def register_service_handler(service_type: str, handler_class: type) -> None:
        """注册服务处理器
        
        Args:
            service_type: 服务类型
            handler_class: 处理器类
        """
        ServiceHandlerFactory.register_handler(service_type, handler_class)
    
    @staticmethod
    def register_formatter(format_type: str, formatter_class: type) -> None:
        """注册报告格式化器
        
        Args:
            format_type: 报告格式类型
            formatter_class: 格式化器类
        """
        ReporterFactory.register_formatter(format_type, formatter_class) 